package com.luych.toolbox.base.service.service;

import com.luych.toolbox.base.service.constant.Constant;
import com.luych.toolbox.base.service.dao.LetterDao;
import com.luych.toolbox.base.service.entity.Letter;
import com.luych.toolbox.common.feign.param.base.service.LetterParam;
import com.luych.toolbox.common.feign.view.base.service.LetterView;
import com.luych.toolbox.common.feign.view.base.service.UserView;
import com.luych.toolbox.common.page.PageParam;
import com.luych.toolbox.common.page.PageResult;
import com.luych.toolbox.common.service.base.BaseConvert;
import com.luych.toolbox.common.service.base.BaseService;
import com.luych.toolbox.common.service.exception.HttpException;
import com.luych.toolbox.common.service.page.SpringPageParamAdapter;
import com.luych.toolbox.common.service.page.SpringPageResultAdapter;
import com.luych.toolbox.common.service.security.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class LetterService extends BaseService<LetterView, LetterParam, Letter> {

    private static final BaseConvert<LetterParam, Letter> letterParamToEntity = Letter::new;
    private static final BaseConvert<Letter, LetterView> letterEntityToView = LetterView::new;

    private final LetterDao letterDao;

    @Autowired
    public LetterService(LetterDao letterDao) {
        super(letterDao, letterParamToEntity, letterEntityToView);
        this.letterDao = letterDao;
    }

    @Override
    public LetterView create(LetterParam param) {
        Letter entity = letterParamToEntity.apply(param);
        entity.setReaded(false);
        entity = letterDao.save(entity);
        return letterEntityToView.apply(entity);
    }

    @Override
    public LetterView modify(LetterParam param) {
        throw new HttpException(HttpStatus.BAD_REQUEST, Constant.LETTER_MODIFY_UNSUPPORTED);
    }

    @Override
    public void remove(String id) {
        Optional<Letter> letter = letterDao.findById(id);
        if (letter.isPresent()) {
            UserView session = SecurityUtil.getSession();
            if (!letter.get().getUserId().equals(session.getId())) {
                throw new HttpException(HttpStatus.FORBIDDEN, Constant.LETTER_DELETE_REJECT_OTHER);
            }
        }
        letterDao.deleteById(id);
    }

    public PageResult<LetterView> pageByKeyword(PageParam pageParam, String keyword, Boolean readed) {
        UserView session = SecurityUtil.getSession();
        Specification<Letter> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate userEqual = criteriaBuilder.equal(root.get("userId"), session.getId());
            predicates.add(userEqual);
            if (!StringUtils.isEmpty(keyword)) {
                Predicate messageLike = criteriaBuilder.like(root.get("message"), '%' + keyword + '%');
                Predicate contentLike = criteriaBuilder.like(root.get("content"), '%' + keyword + '%');
                Predicate keywordLike = criteriaBuilder.or(messageLike, contentLike);
                predicates.add(keywordLike);
            }
            if (readed != null) {
                Predicate readedEqual = criteriaBuilder.equal(root.get("readed"), readed);
                predicates.add(readedEqual);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        Page<Letter> page = letterDao.findAll(specification, new SpringPageParamAdapter(pageParam));

        PageResult<Letter> pageResult = new SpringPageResultAdapter<>(page);
        return pageResult.convert(letterEntityToView).convert(this::fill);
    }

    private Letter getAndCheck(String id) {
        Optional<Letter> letter = letterDao.findById(id);
        if (!letter.isPresent()) {
            throw new HttpException(HttpStatus.NOT_FOUND, Constant.LETTER_NOT_FOUND);
        }
        UserView session = SecurityUtil.getSession();
        if (!letter.get().getUserId().equals(session.getId())) {
            throw new HttpException(HttpStatus.FORBIDDEN, Constant.LETTER_OPERATE_REJECT_OTHER);
        }
        return letter.get();
    }

    public void setReaded(String id) {
        Letter letter = this.getAndCheck(id);
        letter.setReaded(true);
        letterDao.save(letter);
    }

    public void setUnread(String id) {
        Letter letter = this.getAndCheck(id);
        letter.setReaded(false);
        letterDao.save(letter);
    }

    public int setReadedAll() {
        UserView session = SecurityUtil.getSession();
        return letterDao.setAllReaded(session.getId());
    }

    public int setUnreadAll() {
        UserView session = SecurityUtil.getSession();
        return letterDao.setAllUnread(session.getId());
    }

    public int deleteReaded() {
        UserView session = SecurityUtil.getSession();
        return letterDao.removeAllReaded(session.getId());
    }

    public int deleteUnread() {
        UserView session = SecurityUtil.getSession();
        return letterDao.removeAllUnread(session.getId());
    }

    public int deleteAll() {
        UserView session = SecurityUtil.getSession();
        return letterDao.removeAll(session.getId());
    }
}
